package ccore

import (
	"encoding/csv"
	"fmt"
	"io"
	"ll_csv_con/cutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"
)

var (
	filecache       map[string][]string //存放文件2的数据，转换成hash
	targetIndex1    int                 //我们的目标的所属的列 下标（索引）
	targetIndex2    int                 //我们的目标的所属的列 下标（索引）
	title2          []string            // 记录一下csv2 的title
	csvRecordChanHb chan []string       //csv 新数据（行）
	NewFileNameHb   string
	wghb            sync.WaitGroup
)

func init() {
	filecache = make(map[string][]string)
	csvRecordChanHb = make(chan []string, 10)
}

/**
 * target1 == target2
 * 笛卡尔积，相对生成
 */
func Hb(csv1path string, csv2path string, target1 string, target2 string) {
	//生成缓存
	readCsvCace(csv2path, target2)
	//fmt.Println(filecache)
	wghb.Add(1)
	go getNewRecord(csv1path, target1)

	wghb.Add(1)
	go writeCsvChanHb()

	wghb.Wait()
	println(NewFileNameHb + "文件已经生成成功，请查阅")
}

//从csv1 和 filecache ，组成新的 record，入chan
func getNewRecord(csvpath string, target string) {
	if NewFileName == "" {
		//获取新的名字
		NewFileNameHb = GetNewFilenameHb(csvpath)
	}
	//如果文件存在，删除
	if cutil.CheckFileIsExist(NewFileNameHb) {
		err := os.Remove(NewFileNameHb)
		if err != nil {
			// 删除失败
			log.Fatalln("Couldn't delete the NewFileNameHb file", err)
		}
	}

	csvfile, err := os.Open(csvpath)
	if err != nil {
		log.Fatalln("Couldn't open the csv file", err)
	}
	defer csvfile.Close()
	// Parse the file
	r := csv.NewReader(csvfile)
	r.FieldsPerRecord = -1
	isfisrt := true
	// Iterate through the records
	for {
		// Read each record from csv
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		//首行特殊处理
		if isfisrt {
			//获取目标的索引
			targetIndex1 = getTargetIndex(record, target)
			if targetIndex1 == -1 {
				fmt.Println("csv1 没有这个目标列" + target)
				os.Exit(0)
			}
			//合并两个csv 的 title
			newTitle := append(record, title2...)
			//首行直接写入新文件
			writeCsv(NewFileNameHb, newTitle)
			isfisrt = false
			continue
		}
		//其他的数据，查询cache 合并数据
		cvs2record, ok := filecache[record[targetIndex1]]
		var newRecord []string
		if ok {
			newRecord = append(record, cvs2record...)
		} else {
			newRecord = record
		}
		csvRecordChanHb <- newRecord
	}
	close(csvRecordChanHb)
	wghb.Done()
}

//结果写入新的文件
func writeCsvChanHb() {
	time.Sleep(time.Second)
	nfs, err := os.OpenFile(NewFileNameHb, os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		log.Fatalf("writeCsvChan can not create file, err is %+v , FILENAME IS %+v", err, NewFileNameHb)
	}
	defer nfs.Close()
	nfs.Seek(0, io.SeekEnd)

	w := csv.NewWriter(nfs)
	//设置属性
	w.Comma = ','
	w.UseCRLF = true

	for {
		if cv, ok := <-csvRecordChanHb; ok {
			//写入文件
			err = w.Write(cv)
			if err != nil {
				log.Fatalf("can not write, err is %+v", err)
			}
			//这里必须刷新，才能将数据写入文件。
			w.Flush()
		} else {
			break
		}
	}
	wghb.Done()
}

//读取csv 的内容，用hash 存起来
func readCsvCace(csvpath string, target string) {
	csvfile, err := os.Open(csvpath)
	if err != nil {
		log.Fatalln("Couldn't open the csv file", err)
	}
	defer csvfile.Close()

	// Parse the file
	r := csv.NewReader(csvfile)
	r.FieldsPerRecord = -1
	isfisrt := true
	// Iterate through the records
	for {

		// Read each record from csv
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		//首行特殊处理
		if isfisrt {
			//获取目标的索引
			targetIndex2 = getTargetIndex(record, target)
			//fmt.Println("csv2 targetIndex2" + strconv.Itoa(targetIndex2)  )
			if targetIndex2 == -1 {
				fmt.Println("csv2 没有这个目标列" + target)
				os.Exit(0)
			}
			title2 = record
			isfisrt = false
			continue
		}
		//fmt.Println(targetIndex2,record)
		//放在缓存里面,用目标的值做key，可以会很大，不过没有办法
		if targetIndex2 >= len(record) {
			continue
		} else {
			filecache[record[targetIndex2]] = record
		}
	}
}

func GetNewFilenameHb(oldName string) string {
	paths, filename := filepath.Split(oldName)
	filenameWithSuffix := path.Base(oldName)                 //获取文件名带后缀
	fileSuffix := path.Ext(filenameWithSuffix)               //获取文件后缀
	filenameOnly := strings.TrimSuffix(filename, fileSuffix) //获取文件名
	return paths + filenameOnly + "_new_hb" + ".csv"
}
